package com.itheima.stock.service.impl;

import com.google.common.collect.Lists;
import com.itheima.stock.entity.StockBlockRtInfo;
import com.itheima.stock.entity.StockMarketIndexInfo;
import com.itheima.stock.entity.StockRtInfo;
import com.itheima.stock.mapper.StockBlockRtInfoMapper;
import com.itheima.stock.mapper.StockBusinessMapper;
import com.itheima.stock.mapper.StockMarketIndexInfoMapper;
import com.itheima.stock.mapper.StockRtInfoMapper;
import com.itheima.stock.properties.MarketProperties;
import com.itheima.stock.service.StockTimerTaskService;
import com.itheima.stock.util.IdWorkers;
import com.itheima.stock.util.ParserStockInfoUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @Author:gzc
 * @Date: 2025/11/11 22:57
 * @Description:
 */
@Service
@Slf4j
public class StockTimerTaskServiceImpl implements StockTimerTaskService {

    @Autowired
    private MarketProperties marketProperties;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private IdWorkers idWorkers;

    @Autowired
    private StockMarketIndexInfoMapper stockMarketIndexInfoMapper;

    @Autowired
    private StockBusinessMapper stockBusinessMapper;

    @Autowired
    private StockRtInfoMapper stockRtInfoMapper;

    @Autowired
    private ParserStockInfoUtil parserStockInfoUtil;

    @Autowired
    private StockBlockRtInfoMapper stockBlockRtInfoMapper;

    @Autowired
    @Qualifier("threadPoolTaskExecutor")
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Override
    public void getInnerMarketInfo() {
        //http://hq.sinajs.cn/list=s_sh000001,s_sz399001
        String innerUrl = marketProperties.getMarketUrl() + String.join(",", marketProperties.getInner());
        //设置请求头信息
        HttpHeaders headers = new HttpHeaders();
        //告诉服务器请求是从哪个页面发起的
        headers.add("Referer", "https://finance.sina.com.cn/stock/");
        //模拟真实浏览器的请求 没有User-Agent或使用默认的Java UA，会被识别为爬虫而拒绝
        headers.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36");
        //发起请求
        String result = restTemplate.postForObject(innerUrl, new HttpEntity<>(headers), String.class);
        //var hq_str_s_sh000001="上证指数,3094.668,-128.073,-3.97,436653,5458126";
        String reg = "var hq_str_(.+)=\"(.+)\";";
        Matcher matcher = Pattern.compile(reg).matcher(result);
        //收集大盘封装后后的对象
        ArrayList<StockMarketIndexInfo> list = new ArrayList<>();
        while (matcher.find()) {
            String[] others = matcher.group(2).split(",");
            //封装对象
            StockMarketIndexInfo stockMarketIndexInfo = StockMarketIndexInfo
                    .builder().id(idWorkers.nextId() + "")
                    .markName(others[0])
                    .tradeVolume(Long.valueOf(others[5]))
                    .tradeAccount(Long.valueOf(others[4]))
                    .updownRate(new BigDecimal(others[3]))
                    .curTime(LocalDateTime.now())
                    .curPoint(new BigDecimal(others[1]))
                    .currentPrice(new BigDecimal(others[2]))
                    .markId(matcher.group(1))
                    .build();
            list.add(stockMarketIndexInfo);
        }

        log.info("集合长度：{}，内容：{}", list.size(), list);
        //批量插入
        if (CollectionUtils.isEmpty(list)) {
            log.info("当前无国内大盘实时数据");
            return;
        }
        String curTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        log.info("采集的大盘数据：{},当前时间：{}", list, curTime);
        int count = stockMarketIndexInfoMapper.insertBatch(list);
        log.info("批量插入了：{}条数据", count);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void getStockRtIndex() {
        //批量获取股票ID集合
        List<String> stockIds = stockBusinessMapper.getStockIds();
        //计算出符合sina命名规范的股票id数据
        stockIds = stockIds.stream().map(id -> id.startsWith("6") ? "sh" + id : "sz" + id)
                .collect(Collectors.toList());
        //设置公共请求头对象
        //设置请求头数据
        HttpHeaders headers = new HttpHeaders();
        headers.add("Referer", "https://finance.sina.com.cn/stock/");
        headers.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36");
        HttpEntity<String> entity = new HttpEntity<>(headers);
        //一次性查询过多，我们将需要查询的数据先进行分片处理，每次最多查询20条股票数据
        Lists.partition(stockIds, 20).forEach(list -> {
            //每个分片的数据开启一个线程异步执行任务
            threadPoolTaskExecutor.execute(() -> {
                //拼接股票url地址
                String stockUrl = marketProperties.getMarketUrl() + String.join(",", list);
                //获取响应数据
                String result = restTemplate.postForObject(stockUrl, entity, String.class);
                List<StockRtInfo> infos = parserStockInfoUtil.parser4StockOrMarketInfo(result, 3);
                log.info("分片数据：{}", infos);
                int count = stockRtInfoMapper.insertBatch(infos);
                log.info("批量插入了{}条数据", count);
            });
        });
    }

    @Override
    public void getStockBlockRtIndex() {
        //发送板块数据请求
        String result = restTemplate.getForObject(marketProperties.getBlockUrl(), String.class);
        //响应结果转板块集合数据
        List<StockBlockRtInfo> infos = parserStockInfoUtil.parse4StockBlock(result);
        log.info("板块数据:{},板块数据量：{}", infos, infos.size());
        Lists.partition(infos, 20).forEach(list -> {
                    threadPoolTaskExecutor.execute(() -> {
                        log.info("线程：{}", Thread.currentThread().getName());
                        //20个一组，批量插入
                        int count = stockBlockRtInfoMapper.insertBatch(list);
                        log.info("一次批量插入了{}条数据", count);
                    });
                }
        );
    }
}
